package ConversationClasses
{
	import CharacterTraits.Personality;
	import ConversationClasses.ConversationStage;
	import Data.Images;
	import org.flixel.*;
	import org.flixel.plugin.photonstorm.FlxButtonPlus;
	import Data.Color;
	import StoryGeneration.Relationship;
	
	public class Conversation extends FlxGroup
	{
		public static var inConversation:Boolean = false;
		public static var npcTalking:Boolean = false;
		public static var lastSpokeTo:String;
		public static var talkingTo:String;
		private var targetCopy:Character;
		private const conversationDelay:Number = 1.0;
		private var stage:String;
		
		private const backroundBoarderBuffer:uint = 20;
		private const backgroundHeight:uint = 150;
		private var background:FlxSprite;
		
		private const npcStatementBuffer:uint = 10;
		private const npcStatementBackgroundHeight:uint = 60;
		private var npcStatementBackground:FlxSprite;
		
		private var npcNameBackground:FlxSprite;
		private var npcNameText:FlxText;
		
		private const npcDisplayUpdateDelay:Number = 0.05;
		private var npcDisplayUpdateTimer:Number = 0.0;
		private var npcTextToDisplay:String = null;
		private var npcConversationText:FlxText;
		
		public function Conversation()
		{
			background = new FlxSprite(backroundBoarderBuffer, FlxG.height - backroundBoarderBuffer / 2 - backgroundHeight, Images.DIALOGUE_BOX);
			background.scrollFactor.x = 0;
			background.scrollFactor.y = 0;
			add(background);
			
			npcStatementBackground = new FlxSprite(backroundBoarderBuffer, background.y - npcStatementBackgroundHeight, Images.RESPONSE_BOX);
			npcStatementBackground.scrollFactor.x = 0;
			npcStatementBackground.scrollFactor.y = 0;
			add(npcStatementBackground);
			
			npcNameBackground = new FlxSprite(FlxG.width / 4, npcStatementBackground.y - 30, Images.NAME_BOX);
			npcNameBackground.scrollFactor.x = 0;
			npcNameBackground.scrollFactor.y = 0;
			add(npcNameBackground);
			
			npcNameText = new FlxText(npcNameBackground.x, npcNameBackground.y, npcNameBackground.width);
			npcNameText.setFormat(null, 20, Color.Black, "center");
			npcNameText.scrollFactor.x = 0;
			npcNameText.scrollFactor.y = 0;
			add(npcNameText);
			
			npcConversationText = new FlxText(npcStatementBackground.x + 5, npcStatementBackground.y + 5, npcStatementBackground.width - 10);
			npcConversationText.setFormat(null, 16, Color.Black);
			npcConversationText.scrollFactor.x = 0;
			npcConversationText.scrollFactor.y = 0;
			add(npcConversationText);
			
			ToggleConversation(false);
		}
		
		override public function update():void 
		{
			super.update();
			
			if (inConversation)
			{
				if (FlxG.keys.justPressed("SPACE")) //display whole npc responce immediately
				{
					npcConversationText.text = npcTextToDisplay;
				}
				
				UpdateResponse();
				
				if (stage == ConversationStage.INTRODUCTION && npcTalking == false)
				{
					//transition in to discussion
					stage = ConversationStage.DISCUSSION;
				}
				
				if (stage == ConversationStage.DISCUSSION)
				{
					UpdateConversation();
				}
			}
			
			ConversationHistory.lastConversationTime += FlxG.elapsed;
		}
		
		public static function GetCharacterName(target:Character):String
		{
			return target.name.getFirstName() + " " + target.name.getLastName();
		}
		
		public function BeginConversation(target:Character, player:Player):void
		{
 			target.currentAction = Character.ACTION_TALKING;
			
			CopyTarget(target);
			
			ToggleConversation(true, target);
			
			target.conversationHistory.totalConversations++;
			
			//updates who the player last spoke to and is currently talking to
			lastSpokeTo = talkingTo;
			talkingTo = target.relationship;
			
			FaceNPCToPlayer(target, player);
			
			npcNameText.text = GetCharacterName(target);
			
			npcNameBackground.color = CharacterSpecific.getColor(target);
			
			CharacterIntroduction(target);
		}
		
		public function UpdateConversation():void
		{
			
		}
		
		private function CopyTarget(target:Character):void
		{
			targetCopy = new Character(target.x, target.y, target.name, target.age, target.gender, target.hairColor, target.eyeColor, target.personality, target.relationship, target.map, null);
		}
		
		private function FaceNPCToPlayer(target:Character, player:Player):void
		{
			if (player.x > target.x + target.width)
			{
				if (player.y + player.height < target.y)
				{
					target.looking = "upRight";
					player.looking = "downLeft";
				}
				else if (player.y > target.y + target.height)
				{
					target.looking = "downRight";
					player.looking = "upLeft";
				}
				else
				{
					target.looking = "right";
					player.looking = "left";
				}
			}
			else if (player.x + player.width < target.x)
			{
				if (player.y + player.height < target.y)
				{
					target.looking = "upLeft";
					player.looking = "downRight";
				}
				else if (player.y > target.y + target.height)
				{
					target.looking = "downLeft";
					player.looking = "upRight";
				}
				else
				{
					target.looking = "left";
					player.looking = "right";
				}
			}
			else
			{
				if (player.y < target.y)
				{
					target.looking = "up";
					player.looking = "down";
				}
				else
				{
					target.looking = "down";
					player.looking = "up";
				}
			}
			
			player.updateAnimations();
		}
		
		private function CharacterIntroduction(target:Character):void
		{
			stage = ConversationStage.INTRODUCTION;
			
			ClearNPCDialogue();
			
			npcTextToDisplay = ParseResponse(Introduction.GetIntroduction(target), target);
		}
		
		private function CharacterConclusion(target:Character):void
		{
			stage = ConversationStage.CONCLUSION;
			
			ClearNPCDialogue();
			
			npcTextToDisplay = Conclusion.GetConclusion(target);
		}
		
		private function UpdateResponse():void
		{
			if (npcTalking)
			{
				npcDisplayUpdateTimer += FlxG.elapsed;
				
				if (npcConversationText.text.length < npcTextToDisplay.length)
				{
					if (npcConversationText.text.length == npcTextToDisplay.length)
					{
						npcTalking = false;
					}
					else if (npcDisplayUpdateTimer >= npcDisplayUpdateDelay)
					{
						npcDisplayUpdateTimer -= npcDisplayUpdateDelay;
						
						npcConversationText.text += npcTextToDisplay.charAt(npcConversationText.text.length);
					}
				}
			}
		}
		
		private function ClearNPCDialogue():void
		{
			npcConversationText.text = "";
			npcTalking = true;
		}
		
		public function EndConversation(target:Character):void
		{
			if (npcConversationText.text == npcTextToDisplay)
			{
				if (stage == ConversationStage.CONCLUSION)
				{
					ConversationHistory.lastConversationTime = 0;
					
					ToggleConversation(false, target);
				}
				else
				{
					CharacterConclusion(target);
				}
			}
			else
			{
				npcConversationText.text = npcTextToDisplay
			}
		}
		
		private function ToggleConversation(setTo:Boolean, target:Character = null):void 
		{
			ClearNPCDialogue();
			
			inConversation = setTo;
			
			background.visible = setTo;
			npcStatementBackground.visible = setTo;
			npcNameBackground.visible = setTo;
			npcNameText.visible = setTo;
			npcConversationText.visible = setTo;
			
			if (target != null && setTo == false)
			{
				//toggle character speaking/movement
				target.idle();
			}
		}
		
		public static function GetRandomPhrase(personality:Personality, ... args):String //If you put any non-Phrases into args you fucked up
		{
			var temp:String = "";
			var possibleGroup:FlxGroup = new FlxGroup();
			
			for (var i:uint = 0; i < args.length; i++) 
			{ 
				if ((personality.GetOpennessLevel() >= Phrase(args[i]).openness.x && personality.GetOpennessLevel() <= Phrase(args[i]).openness.y) && 
					(personality.GetConscientiousnessLevel() >= Phrase(args[i]).conscientiousness.x && personality.GetConscientiousnessLevel() <= Phrase(args[i]).conscientiousness.y) &&
					(personality.GetExtraversionLevel() >= Phrase(args[i]).extraversion.x && personality.GetExtraversionLevel() <= Phrase(args[i]).extraversion.y) &&
					(personality.GetAgreeablenessLevel() >= Phrase(args[i]).agreeableness.x && personality.GetAgreeablenessLevel() <= Phrase(args[i]).agreeableness.y) &&
					(personality.GetNeuroticismLevel() >= Phrase(args[i]).neuroticism.x && personality.GetNeuroticismLevel() <= Phrase(args[i]).neuroticism.y))
				{
					possibleGroup.add(Phrase(args[i]));
				}
			}
			
			if (possibleGroup.length == 0)
			{
				temp = "NO PHRASE"; //result if no acceptable phase is available
			}
			else
			{
				temp = Phrase(possibleGroup.getRandom()).text;
			}
			
			return temp;
		}
		
		private function ParseResponse(string:String, target:Character):String
		{
			/* ********************************
			 * 				Key
			 * %N - NPC's name
			 * %D - detective's name
			 * %V - victim's name
			 * ********************************/
			var myPattern:RegExp;
			
			//replace %N
			myPattern = /%N/g;
			
			while (string.indexOf("%N") != -1)
			{
				string = string.replace(myPattern, GetCharacterName(target));
			}
			
			//replace %D
			myPattern = /%D/g;
			
			while (string.indexOf("%D") != -1)
			{
				string = string.replace(myPattern, CharacterSpecific.getDetectiveName(target));
			}
			
			//replace %V
			myPattern = /%V/g;
			
			while (string.indexOf("%V") != -1)
			{
				string = string.replace(myPattern, Victim.GetName(target));
			}
			
			return string;
		}
	}
}